package com.fy.opengltest.FourBlockCalibrate;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.net.Uri;
import android.opengl.GLES20;
import android.opengl.Matrix;

import com.fy.opengltest.R;
import com.fy.opengltest.ShaderUtils;
import com.fy.opengltest.renderPicture.TextureHelper;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

/**
 * Created by android on 7/21/17.
 */

public class FishCalibrateObject {

    private int programId;

    private int textureId;

    private float[] vertexData = {
            -1f, -1f, 0f,
            1f, -1f, 0f,
            1f, 1f, 0f,
            -1f, 1f, 0f,
    };

    private final short[] indexData = {
            0, 1, 2,
            0, 2, 3,
            2, 1, 0,
            3, 2, 0
    };

    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;

    private float mParam_a = 1.0f;
    private float mParam_b = 1.0f;
    private float mParam_f = 1.0f;
    private float mParam_scale = 1.5f;
    private float mParam_x = 0f;
    private float mParam_y = 0f;

    private final float[] projectionMatrix = new float[16];

    private final float[] modelMatrix = new float[16];

    private final float[] viewMatrix = new float[16];

    private final float[] mvMatrix = new float[16];

    private final float[] mvpMatrix = new float[16];

    private int uMatrixHandle;
    private int aVertexPosition;
    private int aTextureCoord;
    private int uSampler;
    private int uLens;
    private int uFov;

    private float[] mParam_lens = new float[4];

    private float[] mParam_fovs = new float[2];

    private Context context;
    private Uri uri;

    private Point pos;
    private Point size;

    public FishCalibrateObject(Context context, Uri uri) {
        this.context = context;
        this.uri = uri;
    }

    public void initBuffer(){
        if (null == vertexBuffer){
            vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)
                    .order(ByteOrder.nativeOrder())
                    .asFloatBuffer()
                    .put(vertexData);
            vertexBuffer.position(0);
        }

        if (null == indexBuffer){
            indexBuffer = ByteBuffer.allocateDirect(indexData.length * 2)
                    .order(ByteOrder.nativeOrder())
                    .asShortBuffer()
                    .put(indexData);
            indexBuffer.position(0);
        }
    }

    public void initShader(Context context, Uri uri){
        String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.gl_vertex);
        String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.gl_fragment);
        programId = ShaderUtils.createProgram(vertexShader, fragmentShader);

        aVertexPosition = GLES20.glGetAttribLocation(programId, "aVertexPosition");
        aTextureCoord = GLES20.glGetAttribLocation(programId, "aTextureCoord");
        uMatrixHandle = GLES20.glGetUniformLocation(programId, "uMatrix");
        uSampler = GLES20.glGetUniformLocation(programId, "uSampler");
        uLens = GLES20.glGetUniformLocation(programId, "uLens");
        uFov = GLES20.glGetUniformLocation(programId, "uFov");

        if (null != uri)
            textureId = TextureHelper.loadTexture(context, uri);
        else
            textureId = TextureHelper.loadTexture(context, R.raw.dome190_24402400);//R.raw.demo_pic);
    }

    public void init(){
        initBuffer();
        initShader(context, uri);
    }


    public void updateViewport(Point pos, Point size){
        this.pos = pos;
        this.size = size;

        if (null != uri) {
            Bitmap bmp = TextureHelper.getBitmap(context, uri);
            if (null != bmp) {
                updateProjection(bmp.getWidth(), bmp.getHeight(), size.x, size.y);
            }
        } else {
            updateProjection(1, 1, size.x, size.y);
        }
    }

    private void updateProjection(float videoWidth, float videoHeight, int screenWidth, int screenHeight) {
        float screenRatio = (float) screenWidth / screenHeight;
        float videoRatio = (float) videoWidth / videoHeight;
        if (videoRatio > screenRatio) {
            Matrix.orthoM(projectionMatrix, 0, -1f, 1f, -videoRatio / screenRatio, videoRatio / screenRatio, -1f, 1f);
        } else
            Matrix.orthoM(projectionMatrix, 0, -screenRatio / videoRatio, screenRatio / videoRatio, -1f, 1f, -1f, 1f);
    }

    public void draw(){

        int posX = pos.x;
        int posY = pos.y;
        int sizeX = size.x;
        int sizeY = size.y;
        //GLES20.glViewport(width * i, 0, width, height);
        GLES20.glViewport(posX, posY, sizeX, sizeY);
        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
        //GLES20.glScissor(width * i, 0, width, height);
        GLES20.glScissor(posX, posY, sizeX, sizeY);

        GLES20.glUseProgram(programId);

        GLES20.glUniformMatrix4fv(uMatrixHandle, 1, false, projectionMatrix, 0);

        GLES20.glEnableVertexAttribArray(aVertexPosition);
        GLES20.glVertexAttribPointer(aVertexPosition, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer);

        //GLES20.glEnableVertexAttribArray(aTextureCoord);
        //GLES20.glVertexAttribPointer(aTextureCoord, 2, GLES20.GL_FLOAT, false, 8, textureVertexBuffer);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
        GLES20.glUniform1i(uSampler, 0);

        mParam_lens[0] = mParam_a;
        mParam_lens[1] = mParam_b;
        mParam_lens[2] = mParam_f;
        mParam_lens[3] = mParam_scale;

        GLES20.glUniform4fv(uLens, 1, mParam_lens, 0);

        mParam_fovs[0] = mParam_x;
        mParam_fovs[1] = mParam_y;
        GLES20.glUniform2fv(uFov, 1, mParam_fovs, 0);

        Matrix.multiplyMM(mvMatrix, 0, viewMatrix, 0, modelMatrix, 0);
        // This multiplies the model view matrix by the projection matrix, and stores the result in the MVP matrix
        // (which now contains model * view * projection).
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvMatrix, 0);

        // Pass in the model view matrix
        //GLES20.glUniformMatrix4fv(program.getMVMatrixHandle(), 1, false, mMVMatrix, 0);

        // Pass in the combined matrix.
        GLES20.glUniformMatrix4fv(uMatrixHandle, 1, false, mvpMatrix, 0);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, indexData.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
        GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
    }

}
